package com.start.admin;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.start.admin.entity.StartSysMenu;
import com.start.admin.security.StartAdminUserDetailService;
import com.start.admin.service.StartSysMenuService;
import com.start.common.exceptions.StartBusException;
import com.start.common.registers.StartBaseRegister;
import com.start.core.annotations.RegisterMenu;
import com.start.core.annotations.RegisterPermission;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 自动配置
 * 并配置自动注册菜单
 */

@Slf4j
@Configuration
@ComponentScan("com.start.admin.**")
@MapperScan({"com.start.admin.mappers.**"})
public class StartAdminAutoConfiguration implements StartBaseRegister {

    @Autowired
    private StartSysMenuService startSysMenuService;

    private List<StartSysMenu> allMenus = new ArrayList<>();
    private boolean initState = false;

    @Override
    public void init() {
        allMenus = startSysMenuService.list();
        initState = true;
    }



    @Bean
    @ConditionalOnMissingBean
    public StartAdminUserDetailService startAdminUserDetailService(){
        return new StartAdminUserDetailService();
    }

    /**
     * 获取初始化状态
     *
     * @return
     */
    @Override
    public boolean getInitState() {
        return initState;
    }

    @Override
    public Class getAnnotationsClass() {
        return RegisterMenu.class;
    }

    @Override
    @Transactional
    public void register(Class clazz) throws Exception {
        log.info("注册菜单中：" + clazz.getSimpleName());
        RegisterMenu annotation = (RegisterMenu) clazz.getAnnotation(RegisterMenu.class);
        if (annotation == null) return;
        if (StringUtils.isEmpty(annotation.systemCode()))
            throw new StartBusException(clazz.getSimpleName() + "系统创建菜单编码不能为空！");
        if (StringUtils.isEmpty(annotation.value())) throw new StartBusException(clazz.getSimpleName() + "菜单名称不能为空");
        StartSysMenu startSysMenu = registerMenu(annotation);
        registerPermission(clazz, startSysMenu.getId());
    }



    /**
     * 销毁
     */
    @Override
    public void destroy() {
        allMenus.clear();
        System.gc();
    }

    /**
     * 注册菜单
     *
     * @param annotation
     * @return
     */
    private StartSysMenu registerMenu(RegisterMenu annotation) {
        List<StartSysMenu> oldMenuList = allMenus.stream().filter(e -> !StringUtils.isEmpty(e.getSystemCode()) && e.getSystemCode().equals(annotation.systemCode())).collect(Collectors.toList());
        if (oldMenuList.size() > 0) {
            return oldMenuList.get(0);
        }
        StartSysMenu startSysMenu = new StartSysMenu();
        startSysMenu.setSystemCode(annotation.systemCode());
        startSysMenu.setIsSystemAdd(true);
        startSysMenu.setLabel(annotation.value());
        startSysMenu.setDirectionType(annotation.directionType());
        startSysMenu.setOpenType(annotation.openType());
        startSysMenu.setCreateBy(String.valueOf(1));
        startSysMenu.setComponent(annotation.component());
        startSysMenu.setPath(annotation.path());
        String parentId = StringUtils.isEmpty(annotation.parentId()) ? null : annotation.parentId().trim();
        if (!StringUtils.isEmpty(parentId)) {
            startSysMenu.setParentId(parentId);
        }
        startSysMenuService.save(startSysMenu);
        allMenus.add(startSysMenu);
        log.warn("菜单注册成功：" + startSysMenu.getLabel());
        return startSysMenu;
    }

    /**
     * 注册权限按钮
     *
     * @param clazz
     * @param menuParentId
     */
    private void registerPermission(Class clazz, String menuParentId) {
        if (StringUtils.isEmpty(menuParentId)) return;
        Method[] methods = clazz.getMethods();
        if (methods.length < 1) return;
        List<Method> collect = Arrays.stream(methods).filter(method -> method.getDeclaredAnnotation(RegisterPermission.class) != null).collect(Collectors.toList());
        if (collect.size() < 1) return;
        List<StartSysMenu> menus = collect.stream()
                .map(m -> m.getAnnotation(RegisterPermission.class))
                .filter(a -> !StringUtils.isEmpty(a.value()))
                .map(a -> {
                    StartSysMenu startSysMenu = new StartSysMenu();
                    startSysMenu.setIsSystemAdd(true);
                    startSysMenu.setType(1);
                    startSysMenu.setLabel(a.name());
                    startSysMenu.setParentId(menuParentId);
                    startSysMenu.setCreateBy(String.valueOf(1));
                    startSysMenu.setCode(a.value());
                    return startSysMenu;
                }).collect(Collectors.toList());

        if (menus.size() < 1) return;
        LambdaQueryWrapper<StartSysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StartSysMenu::getType, 1);

        List<StartSysMenu> oldMenuBtns = allMenus.stream().filter(e -> e.getType() == 1).collect(Collectors.toList());
        Map<String, List<StartSysMenu>> btnsMap = oldMenuBtns.stream().collect(Collectors.groupingBy(StartSysMenu::getCode));
        List<StartSysMenu> newMenuBtns = menus.stream().filter(e -> !btnsMap.containsKey(e.getCode())).collect(Collectors.toList());
        if (newMenuBtns.size() < 1) return;
        startSysMenuService.saveBatch(newMenuBtns);
        allMenus.addAll(newMenuBtns);
    }
}
